package com.aaron.development.hangman.client;

import java.util.ArrayList;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.user.client.Random;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DecoratorPanel;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;

/** TODO Once the game has started remove the add/remove user options and just display
user info.

TODO When the start game button is selected show an input and select the user to choose 
the word.

TODO When the word has been entered and submited, rotate through the other users giving 
them guesses.

TODO Add click handlers like the one for wordSubmit
*/

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class HangMan implements EntryPoint {

	// TODO Clean this up a little, break them up into regions of the code they are used for
	private VerticalPanel userPanel = new VerticalPanel();
	private VerticalPanel gamePanel = new VerticalPanel();
	private HorizontalPanel addPanel = new HorizontalPanel();
	private TextBox newUserTextBox = new TextBox();
	private Button addUserButton = new Button("Submit");
	private Button startGameButton = new Button("Start Game");
	private FlexTable userNamesTable = new FlexTable();
	private ArrayList<String> usernames = new ArrayList<String>();
	private HorizontalPanel mainPanel = new HorizontalPanel();
	private DecoratorPanel userHolder = new DecoratorPanel();
	private String hangManUser = new String();
	private TextBox hangManWord = new TextBox();
	private DialogBox userAndMessage = new DialogBox();
	private Button submitButton = new Button("Submit");
	
	// Dialog Guessing box
	private DialogBox guessingDialog = new DialogBox();
	private int guessingUserIndex = 0;
	private VerticalPanel guessingPanel = new VerticalPanel();
	private TextBox characterGuess = new TextBox();
	private Button submitGuess = new Button("Guess");
	
	/**
	 * This is the entry point method.
	 */
	public void onModuleLoad() {
		// Attach the user list to the decorator panel
		userHolder.setWidget(userPanel);		
		
		// Create section for adding users
		createPanelForUserAddition();
	    
		// Create section for game display
		createGameDisplay();
		
	    // Set the userPanel on the left side of the screen
		mainPanel.add(userHolder);
	    
	    // Set the right side of the screen
		mainPanel.add(gamePanel);
	    
	    // Attach the horizontal split widget to the display.
	    RootPanel.get("playerList").add(mainPanel);
	    
	    // Add the click listener to the addUserButton
	    eventHandlingForUserAddButton();

	    // Listen for keyboard events in the input box.
	    eventHandlingForUserNameKeyPress();
	}
	
	private void createGameDisplay() {
		// Create the start game button
		gamePanel.add(startGameButton);
		
		startGameButton.addClickHandler(startGameClick);
	}
	
	ClickHandler startGameClick = new ClickHandler() {
		@Override
		public void onClick(ClickEvent event) {
			if (usernames.size() > 1) {				
				// Remove the start button, might change this to just hide it
				startGameButton.setVisible(false);
				
				// Set up widgets and panels
				Button closeDialogBox = new Button("Cancel");
				Label userToEnterWord = new Label();
				VerticalPanel dialogPanel = new VerticalPanel();
				HorizontalPanel dialogButtonPanel = new HorizontalPanel();
				
				// Set up title and animation for dialog box and center it
				userAndMessage.setText("Remote Procedure Call");
				userAndMessage.setAnimationEnabled(true);
				userAndMessage.center();
				
				// Add buttons to horizontal panel
				dialogButtonPanel.add(submitButton);
				dialogButtonPanel.add(closeDialogBox);
				
				// Add widgets to vertical panel
				dialogPanel.add(userToEnterWord);
				dialogPanel.add(hangManWord);
				dialogPanel.add(dialogButtonPanel);
				
				hangManWord.setText("Enter word here.");
				hangManUser = usernames.get( Random.nextInt(usernames.size()) );	
				userToEnterWord.setText(hangManUser + " is going to enter the word.");
				
				// Add event handlers for buttons
				submitButton.addClickHandler(wordSubmit);
				closeDialogBox.addClickHandler(hideDialogBox);
				
				userAndMessage.setWidget(dialogPanel);								
				userAndMessage.show();
				
				// Set search box focus and select all
				hangManWord.setFocus(true);
				hangManWord.selectAll();
				
			    // Listen for keyboard events in the input box.
				hangManWord.addKeyPressHandler(enterSubmittedWord);
				
			} else {
				Window.alert("You need at least two users to play.");
			}
			
		}
		
	};
	
	ClickHandler hideDialogBox = new ClickHandler() {
		@Override
		public void onClick(ClickEvent event) {
			userAndMessage.hide();
			startGameButton.setVisible(true);
		}		
	};
	
	KeyPressHandler enterSubmittedWord = new KeyPressHandler() {
		public void onKeyPress(KeyPressEvent event) {
			if (event.getCharCode() == KeyCodes.KEY_ENTER) {
				handleSubmittedWord();
			}
		}		
	};
	
	ClickHandler wordSubmit = new ClickHandler() {
		public void onClick(ClickEvent event) {			
			handleSubmittedWord();
		}
	};
	
	private void handleSubmittedWord() {
		// Check if we have already added the word
		submitButton.setEnabled(false);
		
		String wordSubmitted = hangManWord.getText();
		// Make sure we have a word that is all characters
		if (! wordSubmitted.matches("^[a-zA-Z]+$") ) {
			Window.alert("This is not a valid word, try again.");
			
			// Re-enable button if the submission failed
			submitButton.setEnabled(true);
		} else {			
			// Create the world holder
			String underScores = "";
			for( int i = 0; i < wordSubmitted.length(); i++ ) {
				underScores += " _ ";
			}
			
			Label wordUnderScores = new Label(underScores);
			
			// Place the underscored in the game panel.
			gamePanel.add(wordUnderScores);
			
			// Hide the dialog window
			userAndMessage.hide();
			
			// Now we want to diplay the screen for guessing.
			createGuessingDialogWindow();
		}		
	}
	
	private void createGuessingDialogWindow() {
		// Get the username and set the guessingUserIndex one position forward or rotate
		
		guessingPanel.add(new Label("Aaron"));
		guessingPanel.add(characterGuess);
		guessingPanel.add(submitGuess);
		
		guessingDialog.setText("Guess a letter");
		guessingDialog.setAnimationEnabled(true);
		guessingDialog.setWidget(guessingPanel);
		guessingDialog.show();
	}
	
	private void createPanelForUserAddition() {
		// Create table do display users names
		userNamesTable.setText(0, 0, "Player Name");

	    // Assemble Add Stock panel.
	    addPanel.add(newUserTextBox);
	    addPanel.add(addUserButton);

	    // Assemble Main panel.
	    userPanel.add(userNamesTable);
	    userPanel.add(addPanel);		
	}
	
	private void eventHandlingForUserNameKeyPress() {
	    newUserTextBox.addKeyPressHandler(new KeyPressHandler() {
	      public void onKeyPress(KeyPressEvent event) {
	        if (event.getCharCode() == KeyCodes.KEY_ENTER) {
	          addUser();
	        }
	      }
	    });		
	}
	
	private void eventHandlingForUserAddButton() {
	    addUserButton.addClickHandler(new ClickHandler() {
	    	public void onClick(ClickEvent even) {
	    		addUser();
	    	}
	    });		
	}
	
	private void addUser() {
	    final String username = newUserTextBox.getText().toUpperCase().trim();
	    newUserTextBox.setFocus(true);

	    if (! setUserIfValid(username) ) return;

	    newUserTextBox.setText("");

	    // Don't add the username if it's already in the table.
	    if(usernames.contains(username))
	    	return;

	    // Add the username to the table.
	    int row = userNamesTable.getRowCount();
	    usernames.add(username);
	    userNamesTable.setText(row, 0, username);
	    
	    // Add a button to remove this username from the table.
	    createRemoveButtonForUser(username, row);

	}

	private void createRemoveButtonForUser(final String username, int row) {
	    Button removeUserButton = new Button("x");
	    removeUserButton.addClickHandler(new ClickHandler() {
	      public void onClick(ClickEvent event) {
	        int removedIndex = usernames.indexOf(username);
	        usernames.remove(removedIndex);
	        userNamesTable.removeRow(removedIndex + 1);
	      }
	    });
	    userNamesTable.setWidget(row, 1, removeUserButton);
	}
	
	private boolean setUserIfValid(String username) {
	    // username must be between 1 and 10 letters.
	    if (!username.matches("^[a-zA-Z\\.]{1,10}$")) {
	      Window.alert("'" + username + "' is not a valid username.");
	      newUserTextBox.selectAll();
	      return false;
	    }
	    
	    return true;
	}
	
}
